#include <os/debug.h>
#include <os/driver.h>
#include <os/memcache.h>
#include <os/initcall.h>
#include <driver/null.h>
#include <sys/ioctl.h>
#include <lib/string.h>
#include <lib/bitop.h>
#include <lib/list.h>

static iostatus_t NullEntry(driver_object_t *driver)
{
    device_object_t *devobj;
    iostatus_t status;

    status = IoCreateDevice(driver, 0, DEVICE_NAME, DEVICE_TYPE_VIRTUAL_CHAR, &devobj);
    devobj->flags = 0;
    return status;
}

static iostatus_t NullExit(driver_object_t *driver)
{
    device_object_t *devobj, *next;

    list_traversal_all_owner_to_next_safe(devobj, next, &driver->device_list, list)
    {
        IoDeleteDevice(devobj);
    }
    string_del(&driver->name);
    return IO_SUCCESS;
}

static iostatus_t NullOpen(device_object_t *devobj, io_request_t *ioreq)
{
    iostatus_t status = IO_SUCCESS;

    ioreq->io_status.status = IO_SUCCESS;
    ioreq->io_status.info = 0;
    IoCompleteRequest(ioreq);

    return status;
}

static iostatus_t NullClose(device_object_t *devobj, io_request_t *ioreq)
{
    iostatus_t status = IO_SUCCESS;

    ioreq->io_status.status = IO_SUCCESS;
    ioreq->io_status.info = 0;
    IoCompleteRequest(ioreq);

    return status;
}

static iostatus_t NullWrite(device_object_t *devobj, io_request_t *ioreq)
{
    iostatus_t status = IO_SUCCESS;

    ioreq->io_status.status = IO_SUCCESS;
    ioreq->io_status.info = 0;
    IoCompleteRequest(ioreq);

    return status;
}

static iostatus_t NullDriverFunc(driver_object_t *driver)
{
    iostatus_t status = IO_SUCCESS;

    driver->driver_enter = NullEntry;
    driver->driver_exit = NullExit;

    // dispatch function
    driver->dispatch_fun[IOREQ_OPEN] = NullOpen;
    driver->dispatch_fun[IOREQ_CLOSE] = NullClose;
    driver->dispatch_fun[IOREQ_WRITE] = NullWrite;

    // driver name
    string_new(&driver->name, DRIVER_NAME, DRIVER_NAME_LEN);

    return status;
}

static void __init NullDriverEntry()
{
    if (DriverObjectCreate(NullDriverFunc))
        KPrint(PRINT_ERR "[driver] null driver create failed\n");
}

driver_initcall(NullDriverEntry);